// Copyright Finbuckle LLC, Andrew White, and Contributors.
// Refer to the solution LICENSE file for more information.

namespace Finbuckle.MultiTenant.Abstractions;

/// <summary>
/// Contains contextual multi-tenant information.
/// </summary>
/// <typeparam name="TTenantInfo">The <see cref="TenantInfo"/> derived type.</typeparam>
public class MultiTenantContext<TTenantInfo> : IMultiTenantContext<TTenantInfo>
    where TTenantInfo : TenantInfo
{
    // internal for testing purposes
    internal readonly TTenantInfo? _tenantInfo;

    /// <summary>
    /// Initializes a new instance of the <see cref="MultiTenantContext{TTenantInfo}"/> class
    /// with the specified tenant information.
    /// </summary>
    /// <param name="tenantInfo">The tenant information (may be null if not resolved).</param>
    public MultiTenantContext(TTenantInfo? tenantInfo)
    {
        TenantInfo = tenantInfo;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="MultiTenantContext{TTenantInfo}"/> class
    /// with the specified tenant information, strategy information, and store information.
    /// </summary>
    /// <param name="tenantInfo">The tenant information (may be null if not resolved).</param>
    /// <param name="strategyInfo">The strategy that resolved the tenant (may be null).</param>
    /// <param name="storeInfo">The store that provided the tenant information (may be null).</param>
    public MultiTenantContext(TTenantInfo? tenantInfo, StrategyInfo? strategyInfo, StoreInfo<TTenantInfo>? storeInfo)
    {
        TenantInfo = tenantInfo;
        StrategyInfo = strategyInfo;
        StoreInfo = storeInfo;
    }

    /// <inheritdoc />
    public TTenantInfo? TenantInfo
    {
        get
        {
            if (_tenantInfo != null) return _tenantInfo with { };
            return null;
        }
        init
        {
            if (value != null) _tenantInfo = value with { };
            else _tenantInfo = null;
        }
    }

    /// <inheritdoc />
    public bool IsResolved => TenantInfo != null;

    /// <inheritdoc />
    public StrategyInfo? StrategyInfo { get; init; }

    /// <inheritdoc />
    public StoreInfo<TTenantInfo>? StoreInfo { get; init; }

    /// <inheritdoc />
    TenantInfo? IMultiTenantContext.TenantInfo
    {
        get => TenantInfo;
        init => TenantInfo = value as TTenantInfo;
    }
}